package mongodb;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import model.Attribute;
import model.Database;
import model.Table;

/**
 *
 * @author Merli András-Bertalan
 */
public class MongoDb {

    public static void saveTemporalTable(Database database, List<List<String>> temporalTableValues, String temporalTableName) throws UnknownHostException {
        MongoClient mongo = new MongoClient("localhost", 27017);
        DB db = mongo.getDB(database.getName());
        DBCollection dBCollection = db.getCollection(temporalTableName);

        for (List<String> item : temporalTableValues) {
            BasicDBObject document = new BasicDBObject();
            for (int j = 0; j < item.size(); j++) {
                String value = item.get(j);
                document.put(String.valueOf(j), value);
            }
            dBCollection.insert(document);
        }

        mongo.close();
    }

    public static List<String> getMinFromTemporalTables(Database database, List<String> temporalTableNames, int minAttributeIndex) throws UnknownHostException {
        List<List<String>> minValues = new ArrayList<>(temporalTableNames.size());

        MongoClient mongo = new MongoClient("localhost", 27017);
        DB db = mongo.getDB(database.getName());
        for (String temporalTableName : temporalTableNames) {
            DBCollection dBCollection = db.getCollection(temporalTableName);
            DBObject dBObject = dBCollection.findOne();
            if (dBObject != null) {
                List<String> minValue = new ArrayList<>(dBObject.keySet().size());
                for (String key : dBObject.keySet()) {
                    try {
                        int keyIndex = Integer.valueOf(key);
                        minValue.add(keyIndex, String.valueOf(dBObject.get(key)));
                    } catch (NumberFormatException e) {
//                        Logger.getLogger(QueryView.class.getName()).log(Level.SEVERE, null, e);
                    }
                }
                minValues.add(minValue);
            }
        }

        if (minValues.isEmpty()) {
            mongo.close();
            return null;
        } else {
            String min = minValues.get(0).get(minAttributeIndex);
            int minIndex = 0;
            for (int i = 1; i < minValues.size(); i++) {
                if (min.compareTo(minValues.get(i).get(minAttributeIndex)) > 0) {
                    min = minValues.get(i).get(minAttributeIndex);
                    minIndex = i;
                }
            }

            List<String> minValueToReturn = minValues.get(minIndex);

            // delete min object, collection if its in case
            String minTemporalTableName = temporalTableNames.get(minIndex);
            DBCollection dBCollection = db.getCollection(minTemporalTableName);
            DBObject minObject = dBCollection.findOne();
            dBCollection.remove(minObject);
            if (dBCollection.find().size() == 0) {
                dBCollection.drop();
                temporalTableNames.remove(minIndex);
            }

            mongo.close();
            return minValueToReturn;
        }
    }

    public static void deleteDatabases() throws UnknownHostException {
        MongoClient mongo = new MongoClient("localhost", 27017);
        List<String> databaseNames = mongo.getDatabaseNames();
        for (String databaseName : databaseNames) {
            DB db = mongo.getDB(databaseName);
            db.dropDatabase();
        }
        mongo.close();
    }

    public static void saveDatabases(List<Database> databases) throws UnknownHostException {
        MongoClient mongo = new MongoClient("localhost", 27017);
        for (Database database : databases) {
            DB db = mongo.getDB(database.getName());
            for (Table table : database.getTables()) {
                DBCollection dBCollection = db.getCollection(table.getName());

                List<Attribute> attributes = table.getAttributes();
                List<List<String>> values = table.getValues();
                for (List<String> item : values) {
                    String key = "";
                    String value = "";
                    for (int attributeNr = 0; attributeNr < item.size(); attributeNr++) {
                        String attributeValue = item.get(attributeNr);
                        if (attributes.get(attributeNr).getIsPrimary()) {
                            key = key.concat(attributeValue);
                        } else {
                            if (value.equals("")) {
                                value = attributeValue;
                            } else {
                                value = value.concat(" ").concat(attributeValue);
                            }
                        }
                    }
                    BasicDBObject document = new BasicDBObject();
                    document.put("key", key);
                    document.put("value", value);
                    dBCollection.insert(document);
                }
            }

            for (Table table : database.getIndexTables()) {
                DBCollection dBCollection = db.getCollection(table.getName());

                List<List<String>> values = table.getValues();
                for (List<String> item : values) {
                    String key = item.get(0);
                    String value = item.get(1);
                    BasicDBObject document = new BasicDBObject();
                    document.put("key", key);
                    document.put("value", value);
                    dBCollection.insert(document);
                }
            }
        }
        mongo.close();
    }

    public static void loadContentFromDatabaseToTablesAndIndexTables(List<Database> databases) throws UnknownHostException {
        MongoClient mongo = new MongoClient("localhost", 27017);

        for (Database database : databases) {
            DB db = mongo.getDB(database.getName());
            for (Table table : database.getTables()) {
                DBCollection dBCollection = db.getCollection(table.getName());
                DBCursor dBCursor = dBCollection.find();

                List<Attribute> attributes = table.getAttributes();
                List<List<String>> values = new LinkedList<>();
                while (dBCursor.hasNext()) {
                    DBObject o = dBCursor.next();
                    String key = (String) o.get("key");
                    String value = (String) o.get("value");
                    String[] valueArray = value.split(" ");
                    int valueArrayIndex = 0;
                    List<String> item = new LinkedList<>();
                    for (Attribute attribute : attributes) {
                        if (attribute.getIsPrimary()) {
                            item.add(key);
                        } else {
                            item.add(valueArray[valueArrayIndex]);
                            valueArrayIndex++;
                        }
                    }

                    values.add(item);
                }

                table.setValues(values);
            }

            for (Table table : database.getIndexTables()) {
                DBCollection dBCollection = db.getCollection(table.getName());
                DBCursor dBCursor = dBCollection.find();

                List<List<String>> values = new LinkedList<>();
                while (dBCursor.hasNext()) {
                    DBObject o = dBCursor.next();
                    String key = (String) o.get("key");
                    String value = (String) o.get("value");
                    values.add(Arrays.asList(key, value));
                }

                table.setValues(values);
            }
        }
        mongo.close();
    }

    public static void createIndex(Database database, Table table, Attribute attribute) throws UnknownHostException {
        MongoClient mongo = new MongoClient("localhost", 27017);
        DB db = mongo.getDB(database.getName());
        DBCollection dBCollection = db.getCollection(table.getName());
        dBCollection.createIndex(new BasicDBObject(attribute.getName(), 1));
        mongo.close();
    }

    public static void dropIndex(Database database, Table table, Attribute attribute) throws UnknownHostException {
        MongoClient mongo = new MongoClient("localhost", 27017);
        DB db = mongo.getDB(database.getName());
        DBCollection dBCollection = db.getCollection(table.getName());
        dBCollection.dropIndex(new BasicDBObject(attribute.getName(), 1));
        mongo.close();
    }

    public static boolean isKeyInTable(Database database, Table table, String key) throws UnknownHostException {
        MongoClient mongo = new MongoClient("localhost", 27017);
        DB db = mongo.getDB(database.getName());
        DBCollection dBCollection = db.getCollection(table.getName());
        long count = dBCollection.count(new BasicDBObject("key", key));
        mongo.close();

        return count > 0;
    }

    public static List<String> getIndexValuesByKeyFilter(Database database, Table table, String filter) throws UnknownHostException {
        MongoClient mongo = new MongoClient("localhost", 27017);
        DB db = mongo.getDB(database.getName());
        DBCollection dBCollection = db.getCollection(table.getName());

        DBCursor dBCursor = null;
        if (filter.equals("")) {
            dBCursor = dBCollection.find();
        } else {
            String comparable = filter.substring(2);

            if (filter.startsWith("= ")) {
                dBCursor = dBCollection.find(new BasicDBObject("key", comparable));
            } else if (filter.startsWith("< ")) {
                dBCursor = dBCollection.find(new BasicDBObject("key", new BasicDBObject("$lt", comparable)));
            } else if (filter.startsWith("> ")) {
                dBCursor = dBCollection.find(new BasicDBObject("key", new BasicDBObject("$gt", comparable)));
            } else if (filter.startsWith("L ")) {
                dBCursor = dBCollection.find(new BasicDBObject("key", new BasicDBObject("$regex", comparable)));
            }
        }

        List<String> result = new LinkedList<>();
        for (DBObject dBObject : dBCursor) {
            String s = (String) dBObject.get("value");
            if (s.contains(" ")) {
                result.addAll(Arrays.asList(s.split(" ")));
            } else {
                result.add(s);
            }
        }

        mongo.close();

        return result;
    }
}
